package com.keguoyu.easymvp.ioc.internal

import com.google.common.collect.ImmutableMultimap


data class InvokerInfos(internal val mCacheInfo: ClassMapping,
                        internal val mInvocations: Set<Invocation>) {

  @Transient
  internal lateinit var mClassInvocationMapping: ImmutableMultimap<String, Invocation>

  @Transient
  val classInFile = mCacheInfo.mFileMapping::classInFile

  @Transient
  val classInJar = mCacheInfo.mJarMapping::classInFile

  init {
    init()
  }

  fun init() {
    val classInvocationBuilder = ImmutableMultimap.builder<String, Invocation>()
    mInvocations.forEach {
      classInvocationBuilder.put(it.invoker.className, it)
    }
    mClassInvocationMapping = classInvocationBuilder.build()
  }

  fun invocationForClass(clazz: String): Collection<Invocation>? = mClassInvocationMapping[clazz]
}

data class ClassMapping(internal val mClassJarMapping: Map<String, JarFileOutput>,
                        internal val mClassFileMapping: Map<String, String>) {
  @Transient
  internal lateinit var mJarMapping: ClassFileBiMapping<JarFileOutput>
  @Transient
  internal lateinit var mFileMapping: ClassFileBiMapping<String>

  init {
    init()
  }

  fun init() {
    mJarMapping = ClassFileBiMapping(mClassJarMapping) { it.path }
    mFileMapping = ClassFileBiMapping(mClassFileMapping) { it }
  }

  override fun equals(other: Any?): Boolean {
    if (other === this) {
      return true
    }
    if (other is ClassMapping) {
      return mJarMapping == other.mJarMapping && mFileMapping == other.mFileMapping

    }
    return false
  }


  fun fileForClass(className: String): String? = mClassJarMapping.get(className)?.path
}

internal data class ClassFileBiMapping<F>(val classFileMapping: Map<String, F>) {
  @Transient
  lateinit var fileClassMapping: ImmutableMultimap<String, String>

  constructor(classFileMapping: Map<String, F>, name: (F) -> String) : this(classFileMapping) {
    val fileClassBuilder = ImmutableMultimap.builder<String, String>()
    classFileMapping.forEach { clazz, file ->
      fileClassBuilder.put(name(file), clazz)
    }
    fileClassMapping = fileClassBuilder.build()
  }

  fun classInFile(path: String): Collection<String> = fileClassMapping[path]

  override fun equals(other: Any?): Boolean {
    if (other === this) {
      return true
    }
    if (other is ClassFileBiMapping<*>) {
      val classFileEqual = classFileMapping == other.classFileMapping
      val fileClassEqual = fileClassMapping == other.fileClassMapping
      return classFileEqual && fileClassEqual
    }
    return false
  }
}

data class JarFileOutput(val path: String, val name: String)